//
//  Render.m
//  whfdemo005
//
//  Created by 王洪飞 on 2024/6/16.
//

#import "Render.h"
#import "GLProgram.h"
#import <GLKit/GLKit.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"

@interface Render ()
{
    GLuint vaoId, screenVAO;
    GLKMatrix4 modelViewMatrix;
    GLKMatrix4 projectMatrix;
    CGFloat dWidth, dHeight;
    GLint defaultFBO;
    GLuint framebuffer;
}
@property (nonatomic, strong) GLProgram *program;
@property (nonatomic, strong) GLProgram *baseProgram;
@property (nonatomic, strong) GLKTextureInfo *textureinfo;
@property (nonatomic, strong) GLKTextureInfo *textureinfo1;
@end

@implementation Render

- (instancetype)initWith:(CGFloat)width andHeight:(CGFloat)height
{
    self = [super init];
    if (self) {
        dWidth = width;
        dHeight = height;
        
        [self setupProgram];
        [self setupBaseProgram];
        [self initMVP];
        [self loadTexture1];
        [self prepareData];
        [self prepareScreenData];
//        [self setupFramebuffer];
        
    }
    return self;
}

-(void)setupBaseProgram {
    NSString *vSaderStr = @""
    "#version 300 es\n"
    "layout(location = 0) in vec3 vPos;\n"
    "layout(location = 1) in vec2 vCoord;\n"
    "out vec2 s_coord;\n"
    "void main(){\n"
    "   s_coord = vCoord;\n"
    "   gl_Position = vec4(vPos, 1.0);\n"
//    "   gl_Position = vec4(vPos, 1.0);\n"
    "}";
    NSString *fShaderStr = @""
    "#version 300 es\n"
    "precision mediump float;\n"
    "uniform sampler2D s_texture;\n"
    "in vec2 s_coord;\n"
    "out vec4 fragColor;\n"
    "void main(){\n"
//    "   fragColor = texture(s_texture, s_coord);\n"
    "   fragColor = vec4(1,0,0,1);\n"
    "}";
    self.baseProgram = [[GLProgram alloc] initWithVertexShaderString:vSaderStr fragmentShaderString:fShaderStr];
    if ([self.baseProgram link]) {
        NSLog(@"check link ");
    }
}

-(void)setupProgram{
    NSString *vSaderStr = @""
    "#version 300 es\n"
    "layout(location = 0) in vec3 vPos;\n"
    "layout(location = 1) in vec3 vColor;\n"
    "layout(location = 2) in vec2 vCoord;\n"
    "uniform mat4 projection;\n"
    "uniform mat4 mv;\n"
    "out vec2 s_coord;\n"
    "void main(){\n"
    "   s_coord = vCoord;\n"
    "   gl_Position = projection * mv * vec4(vPos, 1.0);\n"
//    "   gl_Position = vec4(vPos, 1.0);\n"
    "}";
    NSString *fShaderStr = @""
    "#version 300 es\n"
    "precision mediump float;\n"
    "uniform sampler2D s_texture;\n"
    "uniform sampler2D s_texture1;\n"
    "in vec2 s_coord;\n"
    "out vec4 fragColor;\n"
    "void main(){\n"
    "   fragColor = texture(s_texture1, s_coord);\n"
    "}";
    self.program = [[GLProgram alloc] initWithVertexShaderString:vSaderStr fragmentShaderString:fShaderStr];
    if ([self.program link]) {
        NSLog(@"check link ");
        
        
    }
}

-(void)initMVP {
    projectMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(85.0), dWidth / dHeight, 0.1f, 20.0f);
   
    for (int i = 0; i < 4; i++) {
        NSLog(@"%f : %f : %f : %f", projectMatrix.m[i * 4 + 0],
                                    projectMatrix.m[i * 4 + 1],
                                    projectMatrix.m[i * 4 + 2],
                                    projectMatrix.m[i * 4 + 3]);
    }
    modelViewMatrix = GLKMatrix4MakeLookAt(0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    NSLog(@"\n\n\n");
    for (int i = 0; i < 4; i++) {
        NSLog(@"%f : %f : %f : %f", modelViewMatrix.m[i * 4 + 0],
              modelViewMatrix.m[i * 4 + 1],
              modelViewMatrix.m[i * 4 + 2],
              modelViewMatrix.m[i * 4 + 3]);
    }
}

-(void)loadTexture1 {
    GLubyte pixels[] = {
        255,0,0,0,
        0,255,0,0,
        0,0,255,0,
        0,255,255,0,
    };
    GLuint texture, texture1;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}

-(void)loadTexture{
    NSString* filePath = [[NSBundle mainBundle] pathForResource:@"for_test" ofType:@"png"];
    NSString* filePath1 = [[NSBundle mainBundle] pathForResource:@"container" ofType:@"jpg"];
    NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:@(0), GLKTextureLoaderOriginBottomLeft, nil];

    GLKTextureInfo* textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
//    GLKTextureInfo* textureInfo1 = [GLKTextureLoader textureWithContentsOfFile:filePath1 options:options error:nil];
    self.textureinfo = textureInfo;
//    self.textureinfo1 = textureInfo1;
    NSLog(@"load texture %d : %x: %x : %x", textureInfo.name, textureInfo.target, GL_TEXTURE0, GL_TEXTURE_2D);

    NSLog(@"text index == %u : %u", [self.program uniformIndex:@"s_texture"], [self.program uniformIndex:@"s_texture1"]);
}

-(void)prepareData {
    GLfloat vertices[] = {
        -1.0f, 1.0f, 0.0f,      0.0f, 0.0f, 1.0f,       0.0f, 0.0f,//左上
        1.0f, 1.0f, 0.0f,       0.0f, 1.0f, 0.0f,       1.0f, 0.0f,//右上
        -1.0f, -1.0f, 0.0f,     1.0f, 0.0f, 1.0f,       0.0f, 1.0f,//左下
        1.0f, -1.0f, 0.0f,      0.0f, 0.0f, 1.0f,       1.0f, 1.0f,//右下
        0.0f, 0.0f, 1.0f,       1.0f, 1.0f, 1.0f,       0.5f, 0.5f,//顶点
    };
    GLubyte indices[] = {
        0, 3, 2,
        0, 1, 3,
    };
    glGenVertexArrays(1, &vaoId);
    glBindVertexArray(vaoId);
    GLuint vboId, eboId;
    glGenBuffers(1, &vboId);
    glBindBuffer(GL_ARRAY_BUFFER, vboId);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    glGenBuffers(1, &eboId);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (float *)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (float *)NULL + 6);
    glEnableVertexAttribArray(2);
    
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

-(void)prepareScreenData{
    GLuint quadVertices[] = {
        // positions   // texCoords
        -1.0f,  1.0f, 0.0f,  0.0f, 1.0f,
        -1.0f, -1.0f, 0.0f,  0.0f, 0.0f,
         1.0f, -1.0f, 0.0f,  1.0f, 0.0f,

        -1.0f,  1.0f, 0.0f,  0.0f, 1.0f,
         1.0f, -1.0f, 0.0f,  1.0f, 0.0f,
         1.0f,  1.0f, 0.0f,  1.0f, 1.0f
    };
    
    GLuint screenVBO;
    glGenVertexArrays(1, &screenVAO);
    glBindVertexArray(screenVAO);
    
    glGenBuffers(1, &screenVBO);
    glBindBuffer(GL_ARRAY_BUFFER, screenVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    
    glBindVertexArray(0);
    
}
-(void)setupFramebuffer{
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
    
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    //创建一个颜色纹理附着
    GLuint textureColorbuffer;
    glGenTextures(1, &textureColorbuffer);
    glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dWidth, dHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//    glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        NSLog(@"framebuffer is not complete");
    } else {
        NSLog(@"check frame buffer success");
    }
       
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

-(void)draw{
    glClearColor(0.5, 1, 1, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    
    [self.program use];
    
    glBindVertexArray(vaoId);
    GLuint proSlot = [self.program uniformIndex:@"projection"];
    GLuint mvSlot = [self.program uniformIndex:@"mv"];
//    NSLog(@"draw %u : %u", proSlot, mvSlot);
    glUniformMatrix4fv(proSlot, 1, GL_FALSE, (GLfloat *)&projectMatrix.m[0]);
    glUniformMatrix4fv(mvSlot, 1, GL_FALSE, (GLfloat *)&modelViewMatrix.m[0]); 

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL);
    
}

@end
